﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.InteropServices;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using IWshRuntimeLibrary;

namespace KeyboardCount
{
    public partial class Form1 : Form
    {
        //勾子管理类 
        private KeyboardHookLib _keyboardHook = null;
        public keys key = new keys();
        public keys daykey = new keys();
        public Form2 ShowKeyboard = null;
        public TcpClient tcpClient = null;
        public bool IsLogin = false;
        public string username = "";
        public string passwd = "";
        public string path = "";

        public Form1()
        {
            InitializeComponent();
            //安装勾子 
            _keyboardHook = new KeyboardHookLib();
            _keyboardHook.InstallHook(this.OnKeyUp);

            DeserializeRecord("record.dat");
            DateRecord dayRecord = new DateRecord();
            this.daykey = dayRecord.DeserializeRecord(DateTime.Now, daykey);

            this.notifyIcon1.Visible = true;//显示任务栏图标

            string StartUpPath = System.Environment.GetFolderPath(Environment.SpecialFolder.Startup);
            StartUpPath += "\\KeyboardCount.exe.lnk";
            if (System.IO.File.Exists(StartUpPath))
            {
                checkBoxAutoStart.Checked = true;
                checkBoxAutoStart.Text = "取消开机启动";
            }

            CheckAutoLogin();

            path = Application.StartupPath + "\\record.dat";

            //注册热键Alt+K，Id号为102。HotKey.KeyModifiers.Alt也可以直接使用数字1来表示。
            HotKey.RegisterHotKey(Handle, 100, HotKey.KeyModifiers.Alt, Keys.K);

            MemoryOptimization();//内存优化
            timer1.Start();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            //注销Id号为100的热键设定
            HotKey.UnregisterHotKey(Handle, 100);

            //取消勾子 
            if (_keyboardHook != null)
                _keyboardHook.UninstallHook();

            SerializeRecord(path);
            DateRecord dateRecord = new DateRecord();
            this.daykey = dateRecord.CheckNextDay(this.daykey);

            //关闭主窗体时，注销登录
            if (linkLabelLogin.Text != "登录")
            {
                LoginOut();
            }
        }

        /// 
        /// 监视Windows消息
        /// 重载WndProc方法，用于实现热键响应
        /// 
        /// 
        protected override void WndProc(ref Message m)
        {
            const int WM_HOTKEY = 0x0312;
            //按快捷键 
            switch (m.Msg)
            {
                case WM_HOTKEY:
                    switch (m.WParam.ToInt32())
                    {
                        case 100:    //按下的是Alt + K
                            if (ShowKeyboard == null)
                            {
                                buttonShowPictrue_Click(new object(), new EventArgs());
                            }
                                     
                            break;
                    }
                    break;
            }
            base.WndProc(ref m);
        }


        /// <summary> 
        /// 客户端键盘捕捉事件. 
        /// </summary> 
        /// <param name="hookStruct">由Hook程序发送的按键信息</param> 
        /// <param name="handle">是否拦截</param> 
        public void OnKeyUp(KeyboardHookLib.HookStruct hookStruct, out bool handle)
        {
            handle = false; //预设不拦截任何键       
     
            if (hookStruct.flags < 120)
            {
                return;
            }
            
            Keys str = (Keys)hookStruct.vkCode;

            if (hookStruct.vkCode >= 65 && hookStruct.vkCode <= 90)
            {
                key.Letter[hookStruct.vkCode - 65]++;
                daykey.Letter[hookStruct.vkCode - 65]++;
            }
            else if (hookStruct.vkCode >= 48 && hookStruct.vkCode <= 57)
            {
                key.Digital[hookStruct.vkCode - 48]++;
                daykey.Digital[hookStruct.vkCode - 48]++;
            }
            else if (hookStruct.vkCode >= 112 && hookStruct.vkCode <= 123)
            {
                key.Fn[hookStruct.vkCode - 112]++;
                daykey.Fn[hookStruct.vkCode - 112]++;
            }

            switch (str.ToString())
            {
                case "Back": key.BackSpace++; daykey.BackSpace++; break;
                case "LWin": key.caidan++; daykey.caidan++; break;
                case "Capital": key.Caps_lock++; daykey.Caps_lock++; break;
                case "Delete": key.Delete++; daykey.Delete++; break;
                case "Oemplus": key.denghao++; daykey.denghao++; break;
                case "Oemcomma": key.douhao++; daykey.douhao++; break;
                case "Down": key.DownKey++; daykey.DownKey++; break;
                case "Oemtilde": key.dunhao++; daykey.dunhao++; break;
                case "End": key.End++; daykey.End++; break;
                case "Return": key.Enter++; daykey.Enter++; break;
                case "Escape": key.Esc++; daykey.Esc++; break;
                case "Oem1": key.fenhao++; daykey.fenhao++; break;
                case "Home": key.Home++; daykey.Home++; break;
                case "Insert": key.Insert++; daykey.Insert++; break;
                case "OemMinus": key.jianhao++; daykey.jianhao++; break;
                case "OemPeriod": key.juhao++; daykey.juhao++; break;
                case "LMenu": key.LAlt++; daykey.LAlt++; break;
                case "LControlKey": key.LCtrl++; daykey.LCtrl++; break;
                case "Left": key.LeftKey++; daykey.LeftKey++; break;
                case "LShiftKey": key.LShift++; daykey.LShift++; break;
                case "Next": key.PageDown++; daykey.PageDown++; break;
                case "PageUp": key.PageUp++; daykey.PageUp++; break;
                case "Pause": key.PauseBreak++; daykey.PauseBreak++; break;
                case "PrintScreen": key.PrintScreen++; daykey.PrintScreen++; break;
                case "RMenu": key.RAlt++; daykey.RAlt++; break;
                case "RControlKey": key.RCtrl++; daykey.RCtrl++; break;
                case "Right": key.RightKey++; daykey.RightKey++; break;
                case "RShiftKey": key.RShift++; daykey.RShift++; break;
                case "Tab": key.TabKey++; daykey.TabKey++; break;
                case "Up": key.UpKey++; daykey.UpKey++; break;
                case "Oem7": key.yinhao++; daykey.yinhao++; break;
                case "Apps": key.youjian++; daykey.youjian++; break;
                case "Oem6": key.youkuohao++; daykey.youkuohao++; break;
                case "Oem5": key.youxiexian++; daykey.youxiexian++; break;
                case "OemOpenBrackets": key.zuokuohao++; daykey.zuokuohao++; break;
                case "OemQuestion": key.zuoxiexian++; daykey.zuoxiexian++; break;
                case "Space": key.Space++; daykey.Space++; break;
            }

            if (ShowKeyboard != null)
            {
                ShowKeyboard.Show();
            }
        }

        private void buttonStartOrStop_Click(object sender, EventArgs e)
        {
            if (buttonStartOrStop.Text == "停止统计")
            {
                //取消勾子 
                if (_keyboardHook != null)
                    _keyboardHook.UninstallHook();
                buttonStartOrStop.Text = "开始统计";
            }
            else
            {
                //安装勾子 
                _keyboardHook = new KeyboardHookLib();
                _keyboardHook.InstallHook(this.OnKeyUp);
                buttonStartOrStop.Text = "停止统计";
            }
        }

        private void buttonShow_Click(object sender, EventArgs e)
        {
            string filename = "KeyboardCount.txt";
            if (!System.IO.File.Exists(filename))
            {
                System.IO.File.Create(filename);
            }

            string str = "";
            for (int i = 0; i < 26; i++ )
            {
                str += (char)('A' + i) + " = " + key.Letter[i] + "\r\n";
            }
            for (int i = 0; i < 10; i++ )
            {
                str += (char)('0' + i) + " = " + key.Digital[i] + "\r\n";
            }
            for (int i = 0; i < 12; i++ )
            {
                str += "f" + (i + 1).ToString() + " = " + key.Fn[i] + "\r\n";
            }

            str += "Esc" + " = " + key.Esc + "\r\n";
            str += "Tab" + " = " + key.TabKey + "\r\n";
            str += "Caps lock" + " = " + key.Caps_lock + "\r\n";
            str += "Enter" + " = " + key.Enter + "\r\n";
            str += "Space" + " = " + key.Space + "\r\n";
            str += "LShift" + " = " + key.LShift + "\r\n";
            str += "RShift" + " = " + key.RShift + "\r\n";
            str += "LCtrl" + " = " + key.LCtrl + "\r\n";
            str += "RCtrl" + " = " + key.RCtrl + "\r\n";
            str += "LAlt" + " = " + key.LAlt + "\r\n";
            str += "RAlt" + " = " + key.RAlt + "\r\n";
            str += "BackSpace" + " = " + key.BackSpace + "\r\n";
            str += "Delete" + " = " + key.Delete + "\r\n";
            str += "Up" + " = " + key.UpKey + "\r\n";
            str += "Down" + " = " + key.DownKey + "\r\n";
            str += "Left" + " = " + key.LeftKey + "\r\n";
            str += "Right" + " = " + key.RightKey + "\r\n";
            str += "Home" + " = " + key.Home + "\r\n";
            str += "PageDown" + " = " + key.PageDown + "\r\n";
            str += "PageUp" + " = " + key.PageUp + "\r\n";
            str += "End" + " = " + key.End + "\r\n";
            str += "Insert" + " = " + key.Insert + "\r\n";
            str += "PrintScreen" + " = " + key.PrintScreen + "\r\n";
            str += "PauseBreak" + " = " + key.PauseBreak + "\r\n";
            str += "、" + " = " + key.dunhao + "\r\n";
            str += "-" + " = " + key.jianhao + "\r\n";
            str += "+" + " = " + key.denghao + "\r\n";
            str += "[" + " = " + key.zuokuohao + "\r\n";
            str += "]" + " = " + key.youkuohao + "\r\n";
            str += "\\" + " = " + key.youxiexian + "\r\n";
            str += "；" + " = " + key.fenhao + "\r\n";
            str += "“" + " = " + key.yinhao + "\r\n";
            str += "，" + " = " + key.douhao + "\r\n";
            str += "。" + " = " + key.juhao + "\r\n";
            str += "/" + " = " + key.zuoxiexian + "\r\n";
            str += "Menu" + " = " + key.caidan + "\r\n";
            str += "RightKey" + " = " + key.youjian + "\r\n";
            System.IO.File.WriteAllText(filename, str);

            SerializeRecord(path);

            System.Diagnostics.Process.Start("notepad.exe ", filename);
        }

        public void SerializeRecord(string filename)
        {
            FileStream file = new FileStream(filename, FileMode.Create);
            BinaryFormatter b = new BinaryFormatter();
            b.Serialize(file, key);
            file.Close();
        }

        public void DeserializeRecord(string filename)
        {
            FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
            BinaryFormatter b = new BinaryFormatter();
            key = b.Deserialize(file) as keys;
            file.Close();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            SerializeRecord(path);
            DateRecord dateRecord = new DateRecord();
            this.daykey = dateRecord.CheckNextDay(daykey);

            MemoryOptimization();//内存优化

            if (IsLogin)//如果处于登录状态，定时同步一次
            {
                Thread thread = new Thread(new ThreadStart(Synchronous));//创建新的线程进行同步，以免主窗体处于阻塞状态
                thread.Start();
            }
        }

        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Hide();
                //this.ShowInTaskbar = false;//隐藏任务栏标签
                this.Text = "";
            }
            else
            {
                //this.ShowInTaskbar = true;
                this.Text = "键盘按键统计";
            }
        }

        private void ToolStripMenuItemShow_Click(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Visible = true;
                this.WindowState = FormWindowState.Normal;
                
                //this.ShowInTaskbar = true;
            }
        }

        private void ToolStripMenuItemExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void notifyIcon1_MouseUp(object sender, MouseEventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized && e.Button == MouseButtons.Left)
            {
                this.Visible = true;
                this.WindowState = FormWindowState.Normal;
                //this.Activate();
                //this.ShowInTaskbar = true;
            }
            this.Activate();
        }

        private void ToolStripMenuItemShowResult_Click(object sender, EventArgs e)
        {
            buttonShow_Click(sender, e);
        }

        private void buttonShowPictrue_Click(object sender, EventArgs e)
        {
            DateRecord dateRecord = new DateRecord();
            this.daykey = dateRecord.CheckNextDay(this.daykey);

            Form2 newForm = new Form2(key, daykey);
            ShowKeyboard = newForm;
            newForm.ShowDialog();
            newForm.Dispose();
            ShowKeyboard = null;
            MemoryOptimization();
        }

        private void ToolStripMenuItemShowKeyboard_Click(object sender, EventArgs e)
        {
            buttonShowPictrue_Click(sender, e);
        }

        private void buttonClear_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("确认清零？", "清零记录", MessageBoxButtons.OKCancel) == DialogResult.OK)
            {
                this.key = new keys();
                SerializeRecord(path);
            }
        }

        private void buttonLoad_Click(object sender, EventArgs e)
        {
            openFileDialog1.Filter = "dat文件(*.dat)|*.dat";
            openFileDialog1.Title = "载入记录";
            openFileDialog1.FileName = "record.dat";
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    DeserializeRecord(openFileDialog1.FileName);
                    SerializeRecord(path);

                    if (IsLogin)
                    {
                        Thread thread = new Thread(new ThreadStart(Synchronous));
                        thread.Start();
                    }      
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show("载入失败！" + ex.Message);
                }
            }
        }

        private void buttonRecord_Click(object sender, EventArgs e)
        {
            saveFileDialog1.Filter = "dat文件(*.dat)|*.dat";
            saveFileDialog1.Title = "备份记录";
            saveFileDialog1.FileName = "record.dat";
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    SerializeRecord(path);
                    SerializeRecord(saveFileDialog1.FileName);

                    if (IsLogin)
                    {
                        Thread thread = new Thread(new ThreadStart(Synchronous));
                        thread.Start();
                    }                    
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show("备份失败！" + ex.Message);
                }                
            }
        }

        private void linkLabelLogin_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            timerCheckLoginOut.Stop();
            SerializeRecord(path);

            if (linkLabelLogin.Text != "登录")
            {
                LoginOut();
                return;
            }

            Login login = new Login();
            login.ShowDialog();

            if (login.IsLoginSuccess)
            {
                username = login.textBoxUserName.Text;
                passwd = login.textBoxPassword.Text;
                tcpClient = login.LoginTcpClient;
                labelUser.Text = "Hello," + login.textBoxUserName.Text.Trim();
                linkLabelLogin.Text = "注销";
                IsLogin = true;
                CheckNew();
            }
        }

        public void LoginOut()
        {
            //退出登录
            try
            {
                SendAndRecrive sendRcv = new SendAndRecrive();
                sendRcv.SendFile(tcpClient, SendAndRecrive.State.LOGOUT);
                tcpClient.Close();
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            labelUser.Text = "";
            IsLogin = false;
            linkLabelLogin.Text = "登录";
        }

        private void linkLabelRegister_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Register register = new Register();
            register.ShowDialog();
        }

        public void CheckNew()
        {
            if (!System.IO.File.Exists("temp\\record.dat"))
            {
                return;
            }

            keys temp = new keys();
            FileStream file = new FileStream("temp\\record.dat", FileMode.Open, FileAccess.Read, FileShare.Read);
            BinaryFormatter b = new BinaryFormatter();
            temp = b.Deserialize(file) as keys;
            file.Close();

            if (Total(key) < Total(temp))
            {
                key = temp;
                SerializeRecord(path);
            }
        }

        public int Total(keys k)
        {
            int total = 0;
            for (int i = 0; i < k.Letter.Length; i++)
            {
                total += k.Letter[i];
            }
            for (int i = 0; i < k.Digital.Length; i++)
            {
                total += k.Digital[i];
            }
            for (int i = 0; i < k.Fn.Length; i++)
            {
                total += k.Fn[i];
            }

            total += k.Esc;
            total += k.TabKey;
            total += k.Caps_lock;
            total += k.LShift;
            total += k.RShift;
            total += k.LCtrl;
            total += k. RCtrl;
            total += k.LAlt;
            total += k.RAlt;
            total += k.BackSpace;
            total += k.Home;
            total += k.PageUp;
            total += k.PageDown;
            total += k.End;
            total += k.Enter;
            total += k.Space;
            total += k.Delete;
            total += k.Insert;
            total += k.PrintScreen;
            total += k.PauseBreak;
            total += k.UpKey;
            total += k.DownKey;
            total += k.LeftKey;
            total += k.RightKey;

            total += k.dunhao;
            total += k.jianhao;
            total += k.denghao;
            total += k.zuokuohao;
            total += k.youkuohao;
            total += k.youxiexian;
            total += k.zuoxiexian;
            total += k.fenhao;
            total += k.yinhao;
            total += k.douhao;
            total += k.juhao;
            total += k.caidan;
            total += k.youjian;

            return total;
        }

        private void checkBoxAutoStart_CheckedChanged(object sender, EventArgs e)
        {
            try
            {
                string StartUpPath = System.Environment.GetFolderPath(Environment.SpecialFolder.Startup);
                StartUpPath += "\\KeyboardCount.exe.lnk";
                if (checkBoxAutoStart.Checked)
                {
                    WshShell shell = new WshShell();
                    IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(StartUpPath);

                    shortcut.TargetPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
                    shortcut.WorkingDirectory = System.Environment.CurrentDirectory;
                    shortcut.Description = "键盘统计程序";
                    shortcut.Save();
                    checkBoxAutoStart.Text = "取消开机启动";
                }
                else
                {
                    System.IO.File.Delete(StartUpPath);
                    checkBoxAutoStart.Text = "设置开机启动";
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("哥们，慢点！我累呀~！~！" + ex.Message);
            }            
        }
    }
}
